package com.sys.aop;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class LogAspect {

    private final ObjectMapper objectMapper;
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    // Mapper 类名映射，提供更友好的显示名称
    private static final Map<String, String> MAPPER_DISPLAY_NAMES = new HashMap<>();
    
    static {
        MAPPER_DISPLAY_NAMES.put("BizTaskMapper", "任务库");
        MAPPER_DISPLAY_NAMES.put("BizPlanMapper", "训练计划");
        MAPPER_DISPLAY_NAMES.put("BizPlanItemMapper", "计划项");
        MAPPER_DISPLAY_NAMES.put("BizTaskLogMapper", "打卡记录");
        MAPPER_DISPLAY_NAMES.put("BizAbilityScoreMapper", "能力评分");
        MAPPER_DISPLAY_NAMES.put("BizGrowthBoxMapper", "成长盒");
        MAPPER_DISPLAY_NAMES.put("BizGrowthBoxItemMapper", "成长盒项");
        MAPPER_DISPLAY_NAMES.put("BizTaskPhotoMapper", "训练照片");
        MAPPER_DISPLAY_NAMES.put("SysUserMapper", "用户");
    }

    public LogAspect(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Pointcut("execution(* com.sys.mapper.*.*(..))")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = null;

        // 获取方法签名
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();

        // 获取简短的类名（去除代理类前缀）
        String className = getSimpleClassName(point.getTarget().getClass());
        
        // 获取友好的显示名称
        String displayName = MAPPER_DISPLAY_NAMES.getOrDefault(className, className);
        
        // 获取操作类型
        String operationType = getOperationType(methodName);

        // 获取请求的参数
        Object[] args = point.getArgs();
        if (args.length > 0) {
            handleTimeField(methodName, args[0]);
        }

        try {
            result = point.proceed();
            
            // 执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;

            // 格式化参数输出
            String formattedArgs = formatArguments(args);
            
            // 根据耗时选择日志级别和格式
            if (time > 1000) {
                log.warn("⚠️  [{}] {} - 耗时: {} ms (较慢) | 方法: {} | 参数: {}", 
                        displayName, operationType, time, methodName, formattedArgs);
            } else if (time > 100) {
                log.info("📊 [{}] {} - 耗时: {} ms | 方法: {} | 参数: {}", 
                        displayName, operationType, time, methodName, formattedArgs);
            } else {
                log.debug("✅ [{}] {} - 耗时: {} ms | 方法: {} | 参数: {}", 
                        displayName, operationType, time, methodName, formattedArgs);
            }
            
        } catch (Throwable e) {
            long time = System.currentTimeMillis() - beginTime;
            log.error("❌ [{}] {} 失败 - 耗时: {} ms | 方法: {} | 错误: {}", 
                    displayName, operationType, time, methodName, e.getMessage());
            throw e;
        }

        return result;
    }

    /**
     * 获取简短的类名（去除代理类前缀和包名）
     */
    private String getSimpleClassName(Class<?> clazz) {
        String className = clazz.getSimpleName();
        
        // 如果是代理类，尝试从接口中获取类名
        if (className.contains("$Proxy")) {
            Class<?>[] interfaces = clazz.getInterfaces();
            if (interfaces.length > 0) {
                className = interfaces[0].getSimpleName();
            }
        }
        
        return className;
    }
    
    /**
     * 根据方法名获取操作类型
     */
    private String getOperationType(String methodName) {
        if (methodName.startsWith("find") || methodName.startsWith("select") || 
            methodName.startsWith("get") || methodName.startsWith("query")) {
            return "查询";
        } else if (methodName.startsWith("insert") || methodName.startsWith("add") || 
                   methodName.startsWith("save") || methodName.startsWith("create")) {
            return "新增";
        } else if (methodName.startsWith("update") || methodName.startsWith("modify") || 
                   methodName.startsWith("edit")) {
            return "更新";
        } else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
            return "删除";
        } else if (methodName.startsWith("count")) {
            return "统计";
        } else {
            return "操作";
        }
    }
    
    /**
     * 格式化参数输出
     */
    private String formatArguments(Object[] args) {
        if (args == null || args.length == 0) {
            return "无";
        }
        
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < args.length; i++) {
                if (i > 0) sb.append(", ");
                
                Object arg = args[i];
                if (arg == null) {
                    sb.append("null");
                } else if (arg instanceof String) {
                    sb.append("\"").append(arg).append("\"");
                } else if (arg instanceof Number || arg instanceof Boolean) {
                    sb.append(arg);
                } else {
                    // 对于复杂对象，只显示类型和部分关键信息
                    String simpleName = arg.getClass().getSimpleName();
                    sb.append(simpleName);
                    
                    // 如果是实体类，尝试获取ID
                    try {
                        Method getId = arg.getClass().getMethod("getId");
                        Object id = getId.invoke(arg);
                        if (id != null) {
                            sb.append("#").append(id);
                        }
                    } catch (Exception ignored) {
                        // 没有getId方法，忽略
                    }
                }
            }
            
            // 限制长度
            String result = sb.toString();
            if (result.length() > 200) {
                return result.substring(0, 197) + "...";
            }
            return result;
            
        } catch (Exception e) {
            return "[格式化失败]";
        }
    }

    /**
     * 自动设置时间字段
     */
    private void handleTimeField(String methodName, Object arg) {
        if (arg == null) {
            return;
        }
        try {
            if (methodName.startsWith("insert") || methodName.startsWith("save")) {
                Method setCreateTime = arg.getClass().getMethod("setCreateTime", LocalDateTime.class);
                setCreateTime.invoke(arg, LocalDateTime.now());
                Method setUpdateTime = arg.getClass().getMethod("setUpdateTime", LocalDateTime.class);
                setUpdateTime.invoke(arg, LocalDateTime.now());
            } else if (methodName.startsWith("update")) {
                Method setUpdateTime = arg.getClass().getMethod("setUpdateTime", LocalDateTime.class);
                setUpdateTime.invoke(arg, LocalDateTime.now());
            }
        } catch (Exception e) {
            // ignore, not all entities have these fields
        }
    }
}